﻿using System;
using Asistente.Model.Representation;

namespace Asistente.Managers
{
    //Clase que interpeta el layout sabiendo como generar un caso de uso
    //segun el caso de uso que se le pasa al metodo NewUseCase y las combinaciones>
    
    //UseCaseComplexity complexity: La entiad procesada en el caso de uso puede ser simple o compuesta
    //UseCaseCardinality cardinality: Se puede editar una entidad o n entidades
    //UseCaseLayout layout: Se presenta la interfaz de usuario con un panel o con dos panels.

    public class UseCaseManager
    {
        private static UseCaseManager _instance = new UseCaseManager();

        public static UseCaseManager Instance
        {
            get
            {
                if (_instance == null)
                    _instance = new UseCaseManager();
                return _instance;
            }
        }

        /// <summary>
        /// Metodo que crea un nuevo caso de uso del tipo que nos pasan por parametro. Asocia 
        /// a el panel principal la entidad que nos pasan por parametro. Toma la complejidad
        /// como Simple, la cardinalidad como One y los paneles como OnePanel
        /// </summary>
        /// <param name="pattern">Patron de caso de uso a crear</param>
        /// <param name="master">Entidad para asociar al panel del caso de uso</param>
        /// <returns>Caso de uso creado</returns>
        public UseCase NewUseCase(UseCasePattern pattern, Entity master)
        {
            return NewUseCase(pattern, master, null, UseCaseComplexity.Simple, UseCaseCardinality.One,
                              UseCaseLayout.OnePanel);
        }

        /// <summary>
        /// Metodo que crea un caso de uso segun los parametros especificados.
        /// </summary>
        /// <param name="pattern">Patron del caso de uso a crear</param>
        /// <param name="master">Entidad master para el caso de uso</param>
        /// <param name="detail">Entidad detali para el caso de uso</param>
        /// <param name="complexity">Complejidad del caso de uso</param>
        /// <param name="cardinality">Cardinaldiad del caso de uso</param>
        /// <param name="layout">Cantidad de paneles del caso de uso</param>
        /// <returns></returns>
        public UseCase NewUseCase(UseCasePattern pattern, Entity master, Entity detail, UseCaseComplexity complexity,
                                  UseCaseCardinality cardinality, UseCaseLayout layout)
        {
            switch (pattern)
            {
                case UseCasePattern.WorkWith:
                    return GetWorkWith(master);
                case UseCasePattern.View:
                    return GetView(master, detail, complexity, cardinality, layout);
                case UseCasePattern.New:
                    return GetNew(master, detail, complexity, cardinality);
                case UseCasePattern.LogicDelete:
                    return GetLogicDelete(master, detail, complexity, cardinality, layout);
                case UseCasePattern.PhysicalDelete:
                    return GetPhysicalDelete(master, detail, complexity, cardinality, layout);
                case UseCasePattern.Update:
                    return GetUpdate(master, detail, complexity, cardinality, layout);
                case UseCasePattern.Search:
                    return GetSearch(master);
                case UseCasePattern.Login:
                    return GetLogin(master);
                case UseCasePattern.List:
                    return GetList(master);
                case UseCasePattern.Configuration:
                    return GetConfiguration(master);
                case UseCasePattern.PasswordChange:
                    return GetPasswordChange(master);
                case UseCasePattern.Empty:
                    return GetEmpty();
                default:
                    throw new NotImplementedException();
            }
        }

        private UseCase GetView(Entity master)
        {
            return GetView(master, null, UseCaseComplexity.Simple, UseCaseCardinality.One, UseCaseLayout.OnePanel);
        }

        public UseCase GetView(Entity master, Entity detail, UseCaseComplexity complexity,
                              UseCaseCardinality cardinality, UseCaseLayout layout)
        {
            var view = new UseCase { Name = Numerator.Instance.GetName(UseCasePattern.View.ToString()), Pattern = UseCasePattern.View };
            view.Description = view.Name;

            Screen screen = view.NewScreen();

            //SIMPLE INDIVIDUAL
            if (complexity == UseCaseComplexity.Simple && cardinality == UseCaseCardinality.One)
            {
                Form form = screen.NewForm();
                form.Entity = master;
                form.NewControl(ControlPattern.PlainTextInput, 5);
            }
            //SIMPLE COLECTIVO
            else if (complexity == UseCaseComplexity.Simple && cardinality == UseCaseCardinality.Many)
            {
                Grid grid = screen.NewGrid();
                grid.Entity = master;
                grid.NewControl(ControlPattern.PlainTextInput, 5);
            }
            //COMPUESTO INDIVIDUAL
            else if (complexity == UseCaseComplexity.Complex && cardinality == UseCaseCardinality.One)
            {
                Form form = screen.NewForm();
                form.Entity = master;
                form.NewControl(ControlPattern.PlainTextInput, 5);

                Grid grid = screen.NewGrid();
                grid.Entity = detail;
                grid.NewControl(ControlPattern.PlainTextInput, 5);
            }
            //COMPUESTO COLECTIVO
            else if (complexity == UseCaseComplexity.Complex && cardinality == UseCaseCardinality.Many)
            {
                Grid grid = screen.NewGrid();
                grid.Entity = master;
                grid.NewControl(ControlPattern.PlainTextInput, 5);

                Grid grid2 = screen.NewGrid();
                grid2.Entity = detail;
                grid2.NewControl(ControlPattern.PlainTextInput, 5);
            }

            //CASO DE QUE SEA 2 PANELES
            //Este caso corresponde a un nuevo panel de seleccion de las instancias que queremos modificar o ver

            if (layout == UseCaseLayout.TwoPanels)
            {
                Grid seleccion = screen.NewGrid();
                seleccion.Entity = master;
                seleccion.NewControl(ControlPattern.PlainTextOutput, 1);
            }

            return view;
        }

        /// <summary>
        /// El caso de uso manual es la base mas simple  para comenzar a definir un caso de uso, corresponde
        /// con un caso de esu de una sola pantalla.
        /// </summary>
        /// <returns>Caso de uso manual</returns>
        private UseCase GetEmpty()
        {
            var empty = new UseCase {Pattern = UseCasePattern.Empty, Name = Numerator.Instance.GetName(UseCasePattern.Empty.ToString())};
            return empty;
        }

        /// <summary>
        /// Para el proceso de baja puede darse de dos maneras, embebido dentro de una visualizacion o 
        /// modificacion (Corresponde a WW). O mediante una busqueda por clave primaria y luego una seleccion. 
        /// </summary>
        private UseCase GetDelete(Entity master, string name, Entity detail, UseCaseComplexity complexity,
                              UseCaseCardinality cardinality, UseCaseLayout layout)
        {
            var delete = new UseCase {Name = name, Description = name};
            
            Screen screen = delete.NewScreen();

            //SIMPLE INDIVIDUAL
            if (complexity == UseCaseComplexity.Simple && cardinality == UseCaseCardinality.One)
            {
                Form form = screen.NewForm();
                form.Entity = master;
                form.NewControl(ControlPattern.PlainTextInput, 5);
            }
            //SIMPLE COLECTIVO
            else if (complexity == UseCaseComplexity.Simple && cardinality == UseCaseCardinality.Many)
            {
                Grid grid = screen.NewGrid();
                grid.Entity = master;
                grid.NewControl(ControlPattern.PlainTextInput, 5);
            }
            //COMPUESTO INDIVIDUAL
            else if (complexity == UseCaseComplexity.Complex && cardinality == UseCaseCardinality.One)
            {
                Form form = screen.NewForm();
                form.Entity = master;
                form.NewControl(ControlPattern.PlainTextInput, 5);

                Grid grid = screen.NewGrid();
                grid.Entity = detail;
                grid.NewControl(ControlPattern.PlainTextInput, 5);
            }
            //COMPUESTO COLECTIVO
            else if (complexity == UseCaseComplexity.Complex && cardinality == UseCaseCardinality.Many)
            {
                Grid grid = screen.NewGrid();
                grid.Entity = master;
                grid.NewControl(ControlPattern.PlainTextInput, 5);

                Grid grid2 = screen.NewGrid();
                grid2.Entity = detail;
                grid2.NewControl(ControlPattern.PlainTextInput, 5);
            }

            //CASO DE QUE SEA 2 PANELES
            //Este caso corresponde a un nuevo panel de seleccion de las instancias que queremos modificar o ver

            if (layout == UseCaseLayout.TwoPanels)
            {
                Grid seleccion = screen.NewGrid();
                seleccion.Entity = master;
                seleccion.NewControl(ControlPattern.PlainTextOutput, 1);
            }

            return delete;
        }

        private UseCase GetLogicDelete(Entity master, Entity detail, UseCaseComplexity complexity,
                              UseCaseCardinality cardinality, UseCaseLayout layout)
        {
            UseCase delete = GetDelete(master, Numerator.Instance.GetName(UseCasePattern.LogicDelete.ToString()),detail,complexity,cardinality,layout);
            delete.Pattern = UseCasePattern.LogicDelete;
            return delete;
        }

        private UseCase GetPhysicalDelete(Entity master, Entity detail, UseCaseComplexity complexity,
                              UseCaseCardinality cardinality, UseCaseLayout layout)
        {
            UseCase delete = GetDelete(master, Numerator.Instance.GetName(UseCasePattern.PhysicalDelete.ToString()), detail, complexity, cardinality, layout);
            delete.Pattern = UseCasePattern.PhysicalDelete;
            return delete;
        }

        public UseCase GetLogin(Entity entity)
        {
            var login = new UseCase {Pattern = UseCasePattern.Login, Name = Numerator.Instance.GetName("Login")};
            login.Description = login.Name;

            Screen loginScreen = login.NewScreen();
            Form form = loginScreen.NewForm();
            form.Entity = entity;

            // User name and pass
            form.NewControl(ControlPattern.PlainTextInput, 2);
            form.NewControl(ControlPattern.CheckBox, 1); // rememberme

            return login;
        }

        public UseCase GetPasswordChange(Entity entity)
        {
            var passChange = new UseCase { Pattern = UseCasePattern.PasswordChange, Name = Numerator.Instance.GetName(UseCasePattern.PasswordChange.ToString()) };
            passChange.Description = passChange.Name;

            Screen screen = passChange.NewScreen();

            Form form = screen.NewForm();
            form.Entity = entity;

            // User name, old pass and new pass
            form.NewControl(ControlPattern.PlainTextInput, 5); // repeted fields

            return passChange;
        }

        /// <summary>
        /// El WW corresponde a una pantalla que muestra la lista de objetos con los cuales queremos trabajar.
        /// Luego contiene botones de accion que seran llamadas a los casos de uso VER NUEVO EDITAR segun corresponde.
        /// </summary>
        /// <param name="master">Entidad a trabajar</param>
        /// <returns></returns>
        public UseCase GetWorkWith(Entity master)
        {
            var ww = new UseCase {Pattern = UseCasePattern.WorkWith, Name = Numerator.Instance.GetName("WorkWith")};
            ww.Description = ww.Name;

            Screen screen = ww.NewScreen();
            Grid grid = screen.NewGrid(); //donde se selecciona la instancia para trabajar
            grid.Entity = master;

            grid.NewControl(ControlPattern.PlainTextInput, 5);

            return ww;
        }

        public UseCase GetNew(Entity master)
        {
            return GetNew(master, null, UseCaseComplexity.Simple, UseCaseCardinality.One);
        }

        /// <summary>
        /// Caso de uso de alta, puede ser simple individual, simple colectivo, compuesto individual
        /// o compuesto colectivo. No hay dos paneles (layout) ya que no seleccionamos ningun objeto.
        /// </summary>
        public UseCase GetNew(Entity master, Entity detail, UseCaseComplexity complexity,
                              UseCaseCardinality cardinality)
        {
            //creamos la instancia con los datos basicos
            var useCase = new UseCase {Pattern = UseCasePattern.New, Name = Numerator.Instance.GetName("New")};
            useCase.Description = useCase.Name;

            Screen screen = useCase.NewScreen();

            //SIMPLE INDIVIDUAL
            if (complexity == UseCaseComplexity.Simple && cardinality == UseCaseCardinality.One)
            {
                Form form = screen.NewForm();
                form.Entity = master;
                form.NewControl(ControlPattern.PlainTextInput, 5);
            }
                //SIMPLE COLECTIVO
            else if (complexity == UseCaseComplexity.Simple && cardinality == UseCaseCardinality.Many)
            {
                Grid grid = screen.NewGrid();
                grid.Entity = master;
                grid.NewControl(ControlPattern.PlainTextInput, 5);
            }
                //COMPUESTO INDIVIDUAL
            else if (complexity == UseCaseComplexity.Complex && cardinality == UseCaseCardinality.One)
            {
                Form form = screen.NewForm(); //master
                form.Entity = master;
                form.NewControl(ControlPattern.PlainTextInput, 5);

                Grid grid = screen.NewGrid(); //detail
                grid.Entity = detail;
                grid.NewControl(ControlPattern.PlainTextInput, 5);
            }
                //COMPUESTO COLECTIVO
            else if (complexity == UseCaseComplexity.Complex && cardinality == UseCaseCardinality.Many)
            {
                Grid grid = screen.NewGrid(); //master
                grid.Entity = master;
                grid.NewControl(ControlPattern.PlainTextInput, 5);

                Grid grid2 = screen.NewGrid(); //detail
                grid2.Entity = detail;
                grid2.NewControl(ControlPattern.PlainTextInput, 5);
            }

            return useCase;
        }

        public UseCase GetUpdate(Entity master)
        {
            return GetUpdate(master, null, UseCaseComplexity.Simple, UseCaseCardinality.One, UseCaseLayout.OnePanel);
        }

        public UseCase GetUpdate(Entity master, Entity detail, UseCaseComplexity complexity,
                                 UseCaseCardinality cardinality, UseCaseLayout layout)
        {
            var useCase = new UseCase {Name = Numerator.Instance.GetName("Update"), Pattern = UseCasePattern.Update};
            useCase.Description = useCase.Name;

            Screen screen = useCase.NewScreen();

            //SIMPLE INDIVIDUAL
            if (complexity == UseCaseComplexity.Simple && cardinality == UseCaseCardinality.One)
            {
                Form form = screen.NewForm();
                form.Entity = master;
                form.NewControl(ControlPattern.PlainTextInput, 5);
            }
                //SIMPLE COLECTIVO
            else if (complexity == UseCaseComplexity.Simple && cardinality == UseCaseCardinality.Many)
            {
                Grid grid = screen.NewGrid();
                grid.Entity = master;
                grid.NewControl(ControlPattern.PlainTextInput, 5);
            }
                //COMPUESTO INDIVIDUAL
            else if (complexity == UseCaseComplexity.Complex && cardinality == UseCaseCardinality.One)
            {
                Form form = screen.NewForm();
                form.Entity = master;
                form.NewControl(ControlPattern.PlainTextInput, 5);

                Grid grid = screen.NewGrid();
                grid.Entity = detail;
                grid.NewControl(ControlPattern.PlainTextInput, 5);
            }
                //COMPUESTO COLECTIVO
            else if (complexity == UseCaseComplexity.Complex && cardinality == UseCaseCardinality.Many)
            {
                Grid grid = screen.NewGrid();
                grid.Entity = master;
                grid.NewControl(ControlPattern.PlainTextInput, 5);

                Grid grid2 = screen.NewGrid();
                grid2.Entity = detail;
                grid2.NewControl(ControlPattern.PlainTextInput, 5);
            }

            //CASO DE QUE SEA 2 PANELES
            //Este caso corresponde a un nuevo panel de seleccion de las instancias que queremos modificar o ver

            if (layout == UseCaseLayout.TwoPanels)
            {
                Grid seleccion = screen.NewGrid();
                seleccion.Entity = master;
                seleccion.NewControl(ControlPattern.PlainTextOutput, 1); //Muestra la clave primaria
            }

            return useCase;
        }

        /// <summary>
        /// El proceso de búsqueda consiste en un conjunto de campos para los atributos de la entidad
        /// a buscar, puede ser solamente la clave primaria o un conjunto de campos. Corresponde con una
        /// pantalla con dos paneles. Uno que contiene los filtros a buscar y una grilla que contiene
        /// el resultado.
        /// </summary>
        /// <param name="entity">Entidad sobre la que buscamos</param>
        /// <returns>Caso de uso de busquda</returns>
        public UseCase GetSearch(Entity entity)
        {
            var search = new UseCase {Name = Numerator.Instance.GetName("Search"), Pattern = UseCasePattern.Search};
            search.Description = search.Name;

            Screen searchScreen = search.NewScreen();
            Filter filters = searchScreen.NewFilter();
            filters.Entity = entity;
            Grid results = searchScreen.NewGrid();
            results.Entity = entity;

            // Search filters
            filters.NewControl(ControlPattern.PlainTextInput, 3);

            // Search results
            results.NewControl(ControlPattern.PlainTextOutput, 5);

            return search;
        }

        /// <summary>
        /// El caso de uso de listado es como una busqueda pero sin condiciones, se puede hacer un
        /// listado de una entidad o de un data group. Los datos recuperados se presentan en un
        /// report, no son editables. Son solamente de salida
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public UseCase GetList(Entity entity)
        {
            var list = new UseCase {Pattern = UseCasePattern.List, Name = Numerator.Instance.GetName("List")};
            list.Description = list.Name;

            Screen listScreen = list.NewScreen();
            Report report = listScreen.NewReport();
            report.DataGroup = entity;

            // ListResults
            report.NewControl(ControlPattern.PlainTextOutput, 5);

            return list;
        }

        public UseCase GetConfiguration(Entity entity)
        {
            var config = new UseCase
                             {
                                 Pattern = UseCasePattern.Configuration,
                                 Name = Numerator.Instance.GetName("Configuration")
                             };

            config.Description = config.Name;

            Screen loginScreen = config.NewScreen();
            Form panel = loginScreen.NewForm();
            panel.Entity = entity;

            //Configuration controls
            panel.NewControl(ControlPattern.PlainTextInput, 2);
            panel.NewControl(ControlPattern.CheckBox, 2);
            panel.NewControl(ControlPattern.RadioButton, 1);
            panel.NewControl(ControlPattern.SlideControl, 1);
            panel.NewControl(ControlPattern.SmallSetMultipleSelector, 1);
            return config;
        }
    }
}